using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.XPath;
using AntEater.ComponentModel.BuildElements;
using System.Xml;
using AntEater.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace AntEater.Runtime.Services.Transformation
{
    /// <summary>
    /// Provides a transfomer for the UsingTaskBuildElement.
    /// </summary>
    [BuildElementTransformer(typeof(UsingTaskBuildElement), XPathNodeType.Element)]
    internal class UsingTaskTransformer:BuildElementTransformerBase
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="T:UsingTaskTransformer"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        public UsingTaskTransformer(object context)
            : base(context) {
        }

        /// <summary>
        /// Transforms an <c>BuildElement</c> into XML.
        /// </summary>
        /// <param name="buildElement">The build element.</param>
        /// <param name="writer">The writer.</param>
        /// <param name="errors">The errors.</param>
        public override void GetXml(IBuildElement buildElement, XmlWriter writer, List<TransformationError> errors) {
            UsingTaskBuildElement element = buildElement as UsingTaskBuildElement;

            if (element != null) {

                BuildElementAttribute buildElementAttribute
                    = ComponentModel.Utilities.GetTypeAttributeFromObject<BuildElementAttribute>(buildElement);

                if (buildElementAttribute != null) {
                    writer.WriteStartElement(buildElementAttribute.Name);

                    bool assemblyNameSpecified = false;
                    bool assemblyFileSpecified = false;

                    if (!string.IsNullOrEmpty(element.AssemblyName)) {
                        writer.WriteAttributeString(this.GetBuildElementPropertyName("AssemblyName"), element.AssemblyName);
                        assemblyNameSpecified = true;
                    }

                   if (!string.IsNullOrEmpty(element.AssemblyFile)) {
                       writer.WriteAttributeString(this.GetBuildElementPropertyName("AssemblyFile"), element.AssemblyFile);
                       assemblyFileSpecified = true;
                    }

                    if (!assemblyNameSpecified && !assemblyFileSpecified) {
                        errors.Add(new TransformationError("AssemblyNameSpecified and AssemblyFileSpecified attribute are not specified! One of these is required.", element));
                    }

                    if (assemblyNameSpecified && assemblyFileSpecified) {
                        errors.Add(new TransformationError("AssemblyNameSpecified and AssemblyFileSpecified attribute are specified! Only one of these is allowed.", element));
                    }

                    if (!string.IsNullOrEmpty(element.TaskName)) {
                        writer.WriteAttributeString(this.GetBuildElementPropertyName("TaskName"), element.TaskName);
                    }
                    else {
                        errors.Add(new TransformationError("TaskName attribute isn't specified!", element));
                    }

                    if (!string.IsNullOrEmpty(element.Condition)) {
                        writer.WriteAttributeString(this.GetBuildElementPropertyName("Condition"), element.Condition);
                    }

                    this.OnGetChildElementsXml(element, writer);

                    writer.WriteEndElement();
                }
            }
        }

        /// <summary>
        /// Gets an <c>BuildElement</c> from XML.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="buildFileDefinition"></param>
        /// <param name="errors">The errors.</param>
        /// <returns></returns>
        public override IBuildElement GetBuildElement(XPathNavigator node, BuildFileDefinition buildFileDefinition, List<TransformationError> errors) {
            UsingTaskBuildElement element = buildFileDefinition.CreateNewBuildElement(typeof(UsingTaskBuildElement)) as UsingTaskBuildElement;

            bool taskNameFound = false;
            bool assemblyNameFound = false;
            bool assemblyFileFound = false;

            if (node.MoveToFirstAttribute()) {
                do {
                    if (node.Name.Equals(this.GetBuildElementPropertyName("AssemblyFile"))) {
                        assemblyFileFound = true;
                        element.AssemblyFile = node.Value;
                    }
                    else if (node.Name.Equals(this.GetBuildElementPropertyName("AssemblyName"))) {
                        assemblyNameFound = true;
                        element.AssemblyName = node.Value;
                    }
                    else if (node.Name.Equals(this.GetBuildElementPropertyName("TaskName"))) {
                        element.TaskName = node.Value;
                        taskNameFound = true;
                    }
                    else if (node.Name.Equals(this.GetBuildElementPropertyName("Condition"))) {
                        element.Condition = node.Value;
                    }
                } while (node.MoveToNextAttribute());
            }

            if (!taskNameFound) {
                errors.Add(new TransformationError("TaskName attribute is missing!", element));
            }

            if (!assemblyNameFound && !assemblyFileFound) {
                errors.Add(new TransformationError("AssemblyName and AssemblyFile attribute are missing! One of these is required.", element));
            }

            if (assemblyNameFound && assemblyFileFound) {
                errors.Add(new TransformationError("AssemblyName and AssemblyFile attribute are present! Only one of these is allowed.", element));
            }

            return element;
        }
    }
}
